home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / tcpout.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-10  |  6.9 KB  |  237 lines

  1. #include "global.h"
  2. #include "timer.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "internet.h"
  6. #include "tcp.h"
  7. #include "ip.h"
  8.  
  9. /*
  10.  * this function processes 'real' 32-bit numbers now - DB3FL.920124
  11.  */
  12. static unsigned long int near
  13. backoff1(int n)
  14. {
  15.     unsigned long int j = 1;
  16.  
  17.     if(n > 31)
  18.         n = 31;
  19.     return (j <<= n);            /* Binary exponential back off */
  20. }
  21.  
  22. /* Send a segment on the specified connection. One gets sent only
  23.  * if there is data to be sent or if "force" is non zero
  24.  */
  25. void
  26. tcp_output(tcb)
  27. struct tcb *tcb;
  28. {
  29.     struct pseudo_header ph;/* Pseudo-header for checksum calcs */
  30.     struct mbuf *hbp,*dbp;    /* Header and data buffer pointers */
  31.     int16 hsize;        /* Size of header */
  32.     struct tcp seg;        /* Local working copy of header */
  33.     int16 ssize;        /* Size of current segment being sent,
  34.                          * including SYN and FIN flags */
  35.     int16 dsize;        /* Size of segment less SYN and FIN */
  36.     int16 usable;        /* Usable window */
  37.     int16 sent;            /* Sequence count (incl SYN/FIN) already in the pipe */
  38.  
  39.     if(tcb == NULLTCB)
  40.         return;
  41.  
  42.     switch(tcb->state){
  43.     case TCP_LISTEN:
  44.     case TCP_CLOSED:
  45.         return;    /* Don't send anything */
  46.     }
  47.     for(;;){
  48.         /* Compute data already in flight */
  49.         sent = tcb->snd.ptr - tcb->snd.una;
  50.  
  51.         /* If transmitter has been idle for more than a RTT,
  52.          * take the congestion window back down to one packet.
  53.          */
  54.         if(!run_timer(&tcb->timer)
  55.          && (msclock() - tcb->lastactive) > tcb->srtt)
  56.             tcb->cwind = tcb->mss;
  57.  
  58.         /* Compute usable send window as minimum of offered
  59.          * and congestion windows, minus data already in flight.
  60.          * Be careful that the window hasn't shrunk --
  61.          * these are unsigned vars.
  62.          */
  63.         usable = min(tcb->snd.wnd,tcb->cwind);
  64.         if(usable > sent)
  65.             usable -= sent;    /* Most common case */
  66.         else if(usable == 0 && sent == 0)
  67.             usable = 1;    /* Closed window probe */
  68.         else
  69.             usable = 0;    /* Window closed or shrunken */
  70.  
  71.         /* Compute size of segment we *could* send. This is the
  72.          * smallest of the usable window, the mss, or the amount
  73.          * we have on hand. (I don't like optimistic windows)
  74.          */
  75.         ssize = min(tcb->sndcnt - sent,usable);
  76.         ssize = min(ssize,tcb->mss);
  77.  
  78.         /* Now we decide if we actually want to send it.
  79.          * Apply John Nagle's "single outstanding segment" rule.
  80.          * If data is already in the pipeline, don't send
  81.          * more unless it is MSS-sized or the very last packet.
  82.          */
  83.         if(sent != 0 && ssize < tcb->mss
  84.          && !(tcb->state == TCP_FINWAIT1 && ssize == tcb->sndcnt-sent)){
  85.             ssize = 0;
  86.         }
  87.          /* Unless the tcp syndata option is on, inhibit data until
  88.          * our SYN has been acked. This ought to be OK, but some
  89.          * old TCPs have problems with data piggybacked on SYNs.
  90.          */
  91.         if(!tcb->flags.synack && !Tcp_syndata){
  92.             if(tcb->snd.ptr == tcb->iss)
  93.                 ssize = min(1,ssize);    /* Send only SYN */
  94.             else
  95.                 ssize = 0;    /* Don't send anything */
  96.         }
  97.         if(ssize == 0 && !tcb->flags.force)
  98.             break;        /* No need to send anything */
  99.  
  100.         tcb->flags.force = 0;    /* Only one forced segment! */
  101.  
  102.         seg.source = tcb->conn.local.port;
  103.         seg.dest = tcb->conn.remote.port;
  104.  
  105.         /* Set the flags according to the state we're in. It is
  106.          * assumed that if this segment is associated with a state
  107.          * transition, then the state change will already have been
  108.          * made. This allows this routine to be called from a
  109.          * retransmission timeout with force=1.
  110.          */
  111.         seg.flags.urg = 0; /* Not used in this implementation */
  112.         seg.flags.rst = 0;
  113.         seg.flags.ack = 1; /* Every state except TCP_SYN_SENT */
  114.         seg.flags.syn = 0; /* syn/fin/psh set later if needed */
  115.         seg.flags.fin = 0;
  116.         seg.flags.psh = 0;
  117.         seg.flags.congest = tcb->flags.congest;
  118.  
  119.         hsize = TCPLEN;    /* Except when SYN being sent */
  120.         seg.mss = 0;
  121.         seg.optlen = 0;
  122.  
  123.         if(tcb->state == TCP_SYN_SENT)
  124.             seg.flags.ack = 0; /* Haven't seen anything yet */
  125.  
  126.         dsize = ssize;
  127.         if(!tcb->flags.synack && tcb->snd.ptr == tcb->iss){
  128.             /* Send SYN */
  129.             seg.flags.syn = 1;
  130.             dsize--;    /* SYN isn't really in snd queue */
  131.             /* Also send MSS */
  132.             seg.mss = Tcp_mss;
  133.             seg.optlen = 0;
  134.             hsize = TCPLEN + MSS_LENGTH;
  135.         }
  136.         seg.seq = tcb->snd.ptr;
  137.         seg.ack = tcb->rcv.nxt;
  138.         seg.wnd = tcb->rcv.wnd;
  139.         seg.up = 0;
  140.  
  141.         /* Now try to extract some data from the send queue. Since
  142.          * SYN and FIN occupy sequence space and are reflected in
  143.          * sndcnt but don't actually sit in the send queue, dup_p
  144.          * will return one less than dsize if a FIN needs to be sent.
  145.          */
  146.         if(dsize != 0){
  147.             int16 offset;
  148.  
  149.             /* SYN doesn't actually take up space on the sndq,
  150.              * so take it out of the sent count
  151.              */
  152.             offset = sent;
  153.             if(!tcb->flags.synack && sent != 0)
  154.                 offset--;
  155.  
  156.             if(dup_p(&dbp,tcb->sndq,offset,dsize) != dsize){
  157.                 /* We ran past the end of the send queue;
  158.                  * send a FIN
  159.                  */
  160.                 seg.flags.fin = 1;
  161.                 dsize--;
  162.             }
  163.         } else {
  164.             dbp = NULLBUF;
  165.         }
  166.         /* If the entire send queue will now be in the pipe, set the
  167.          * push flag
  168.          */
  169.         if(dsize != 0 && sent + ssize == tcb->sndcnt)
  170.             seg.flags.psh = 1;
  171.  
  172.         /* If this transmission includes previously transmitted data,
  173.          * snd.nxt will already be past snd.ptr. In this case,
  174.          * compute the amount of retransmitted data and keep score
  175.          */
  176.         if(tcb->snd.ptr < tcb->snd.nxt)
  177.             tcb->resent += min(tcb->snd.nxt - tcb->snd.ptr,ssize);
  178.  
  179.         tcb->snd.ptr += ssize;
  180.         /* If this is the first transmission of a range of sequence
  181.          * numbers, record it so we'll accept acknowledgments
  182.          * for it later
  183.          */
  184.         if(seq_gt(tcb->snd.ptr,tcb->snd.nxt))
  185.             tcb->snd.nxt = tcb->snd.ptr;
  186.  
  187.         /* Fill in fields of pseudo IP header */
  188.         ph.source = tcb->conn.local.address;
  189.         ph.dest = tcb->conn.remote.address;
  190.         ph.protocol = TCP_PTCL;
  191.         ph.length = hsize + dsize;
  192.  
  193.         /* Generate TCP header, compute checksum, and link in data */
  194.         if((hbp = htontcp(&seg,dbp,&ph)) == NULLBUF){
  195.             free_p(dbp);
  196.             return;
  197.         }
  198.         /* If we're sending some data or flags, start retransmission
  199.          * and round trip timers if they aren't already running.
  200.          */
  201.         if(ssize != 0) {
  202.             /* Set round trip timer */
  203.             unsigned long int srtt;
  204.  
  205.             unsigned long int trtt = 4 * tcb->mdev + tcb->srtt;
  206.             unsigned long int trt1 = backoff1(tcb->backoff) * trtt;
  207.             unsigned long int trt2 = (backoff1(tcb->backoff) - 1) * trtt;
  208.  
  209.             srtt = (trt1 < trt2) ? trt2 : trt1;
  210.  
  211.             if(srtt > 3 * Tcp_irtt)
  212.                 srtt = 3 * Tcp_irtt; /* dc0hk was 5 */
  213.             if(srtt < 500)
  214.                 srtt = 500;    /* dc0hk changed defaults was 2000 */
  215.  
  216.             set_timer(&tcb->timer,srtt);
  217.  
  218.             if(!run_timer(&tcb->timer))
  219.                 start_timer(&tcb->timer);
  220.  
  221.             /* If round trip timer isn't running, start it */
  222.             if(!tcb->flags.rtt_run) {
  223.                 tcb->flags.rtt_run = 1;
  224.                 tcb->rtt_time = msclock();
  225.                 tcb->rttseq = tcb->snd.ptr;
  226.             }
  227.         }
  228.         if(tcb->flags.retran)
  229.             tcpRetransSegs++;
  230.         else
  231.             tcpOutSegs++;
  232.  
  233.         ip_send(tcb->conn.local.address,tcb->conn.remote.address,
  234.             TCP_PTCL,tcb->tos,0,hbp,ph.length,0,0);
  235.     }
  236. }
  237.